/*
 * ringbuf.hpp
 *
 *  Created on: 2015-7-1
 *      Author: work
 */

#ifndef DM_RINGBUF_HPP_
#define DM_RINGBUF_HPP_

#include <dm/ringpos.hpp>

namespace dm{

template<typename Tv,typename Ts,Ts Size,typename Tc=Ts>
class CRingBuf{
	CRingBuf( const CRingBuf& );
	CRingBuf& operator=( const CRingBuf& );

public:
	typedef CRingPos<Ts,Ts,Size,Tc> pos_t;

	CRingBuf():m_p(){}

	inline const Ts getSize()const{
		return Size;
	}

	inline const pos_t& getPos()const{
		return m_p;
	}

	inline Ts getLen( const pos_t& p )const{
		return m_p-p;
	}

	inline Ts getSpace( const pos_t& p )const{
		return getSize() - (m_p - p);
	}

	inline const Tv& dataAt( const Ts& p )const{
		return m_d[p];
	}

	inline const Tv& dataAt( const pos_t& p )const{
		return dataAt(p.getPos());
	}

	inline Ts getData( Tv* buf,const Ts& size,pos_t p )const{
		return getDataAndMovePos(buf,size,p);
	}

	Ts getDataAndMovePos( Tv* buf,Ts size,pos_t& p )const;


	inline void push( const Tv& c ){
		m_d[m_p.getPos()] = c;
		++m_p;
	}

	void push( const Tv* buf,Ts len );

protected:
	Tv m_d[Size];
	pos_t m_p;
};

template<typename Tv,typename Ts,Ts Size,typename Tc>
Ts CRingBuf<Tv,Ts,Size,Tc>::getDataAndMovePos( Tv* buf,Ts size,CRingBuf<Tv,Ts,Size,Tc>::pos_t& pos )const{
	Ts c = 0;
	for( ;c<size && pos!=m_p;++pos,++buf,++c )
		*buf = dataAt(pos.getPos());
	return c;
}

template<typename Tv,typename Ts,Ts Size,typename Tc>
void CRingBuf<Tv,Ts,Size,Tc>::push( const Tv* buf,Ts len ){
	for(;len>0;--len,++buf)
		push(*buf);
}

}

#endif /* RINGBUF_HPP_ */
